#include <os/irq.h>
#include <os/time.h>
#include <os/sched.h>
#include <os/string.h>
#include <os/stdio.h>
#include <assert.h>
#include <sbi.h>
#include <screen.h>

handler_t irq_table[IRQC_COUNT];
handler_t exc_table[EXCC_COUNT];
uintptr_t riscv_dtb;

void reset_irq_timer()
{
    timer_check();
    sbi_set_timer(get_ticks() + TIMER_INTERVAL);
    do_scheduler();
}

void interrupt_helper(regs_context_t *regs, uint64_t stval, uint64_t cause)
{
    uint64_t mask = (1 << 63);
    if(cause >> 63)//scause   
        irq_table[cause & (~mask)](regs,stval,cause);
    else //SCAUSE_IRQ_FLAGæ˜?4'b1000000.....0
        exc_table[cause & (~mask)](regs,stval,cause);
}

void handle_int(regs_context_t *regs, uint64_t interrupt, uint64_t cause)
{
    reset_irq_timer();
}
void handle_inst_page_fault(){

}
void handle_load_page_fault(){

}
void handle_store_page_fault(regs_context_t *regs, uint64_t stval, uint64_t cause){
    //此类例外是向未进行映射的虚拟地址存储数据。stval是要写入的地址。处理的方法是分配一个物理页给该虚拟地址并在页表映射
    alloc_page_helper(stval,current_running->pte_entry);
}
void init_exception()
{
    int i;
    for(i=0;i<IRQC_COUNT;i++)
        irq_table[i]=&handle_other;
    for(i=0;i<EXCC_COUNT;i++)
        exc_table[i]=&handle_other;
    irq_table[5]=&handle_int;
    exc_table[8]=&handle_syscall;
    exc_table[12]=&handle_inst_page_fault;
    exc_table[13]=&handle_load_page_fault;
    exc_table[15]=&handle_store_page_fault;
    setup_exception(&pid0_pcb);
}

void handle_other(regs_context_t *regs, uint64_t stval, uint64_t cause)
{
    // Output more debug information
    char* reg_name[] = {
        "zero "," ra  "," sp  "," gp  "," tp  ",
        " t0  "," t1  "," t2  ","s0/fp"," s1  ",
        " a0  "," a1  "," a2  "," a3  "," a4  ",
        " a5  "," a6  "," a7  "," s2  "," s3  ",
        " s4  "," s5  "," s6  "," s7  "," s8  ",
        " s9  "," s10 "," s11 "," t3  "," t4  ",
        " t5  "," t6  "
    };
    for (int i = 0; i < 32; i += 3) {
        for (int j = 0; j < 3 && i + j < 32; ++j) {
            printk("%s : %016lx ",reg_name[i+j], regs->regs[i+j]);
        }
        printk("\n\r");
    }
    printk("sstatus: 0x%lx sbadaddr: 0x%lx scause: %lx\n\r",
           regs->sstatus, regs->sbadaddr, regs->scause);
    printk("stval: 0x%lx cause: %lx\n\r",
           stval, cause);
    printk("sepc: 0x%lx\n\r", regs->sepc);
    // printk("mhartid: 0x%lx\n\r", get_current_cpu_id());

    uintptr_t fp = regs->regs[8], sp = regs->regs[2];
    printk("[Backtrace]\n\r");
    printk("  addr: %lx sp: %lx fp: %lx\n\r", regs->regs[1] - 4, sp, fp);
    // while (fp < USER_STACK_ADDR && fp > USER_STACK_ADDR - PAGE_SIZE) {
    while (fp > 0x10000) {
        uintptr_t prev_ra = *(uintptr_t*)(fp-8);
        uintptr_t prev_fp = *(uintptr_t*)(fp-16);

        printk("  addr: %lx sp: %lx fp: %lx\n\r", prev_ra - 4, fp, prev_fp);

        fp = prev_fp;
    }

    assert(0);
}
